package com.eairlv.utils.scanner;

import cn.hutool.core.util.ReflectUtil;
import com.eairlv.utils.MSWebMvcConfiguration;
import com.eairlv.utils.utils.LogUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.io.File;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @author lv
 * @create 2018-05-14 13:36
 * @desc
 **/
@Slf4j
public class WebMvcConfigurationScanner {

    private final List<String> classes = new ArrayList<>();

    public Map<Class<?>, ScannerContent> classListMap = new HashMap<>();

    /**
     * 开始扫描
     */
    public void startScanner() {
        try {
            log.info("WebMvcConfigurationScanner is starting");
            ClassLoader cl = getClass().getClassLoader();
            URL url = cl.getResource("");
            String fileUrl = java.net.URLDecoder.decode(url.getFile(),"utf-8");
            log.info("WebMvcConfigurationScanner location: " + fileUrl);
            File[] files = new File(fileUrl).listFiles();
            if (files != null){
                // DEBUG 运行
                findFiles(files);
                classes.forEach(names ->{
                    Class<?> cls = null;
                    try {
                        names = "/" + names.replace("\\", "/");
                        names = names.replace(fileUrl, "");
                        cls = Class.forName(names.replace("/", "."));
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                    if (cls != null){
                        handleClass(cls);
                    }
                });
            } else {
                // JAR 运行
                JarFile jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
                Enumeration<JarEntry> entries = jarFile.entries();
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    try {
                        Class<?> cls = Class.forName(entry.getName().replace("/", ".").replace(".class", ""));
                        handleClass(cls);
                    } catch (ClassNotFoundException ignored) {}
                }
            }
        } catch (Exception e){
            log.warn("startScanner error: {}", LogUtil.getExceptionMessage(e));
        }
    }

    /**
     * 遍历获取所有JAVA文件
     * @param files
     */
    private void findFiles(File[] files){
        for (File file: files) {
            try {
                if (file.isDirectory()){
                    findFiles(Objects.requireNonNull(file.listFiles()));
                } else {
                    if (file.getName().endsWith(".class")){
                        classes.add(file.getAbsolutePath().replace(".class", ""));
                    }
                }
            } catch (Exception e){
                log.warn(e.getMessage());
            }
        }
    }

    /**
     * 处理扫描出来的Class类文件
     * @param cls
     */
    private void handleClass(Class<?> cls){
        if (cls.getSuperclass() != null
                && cls.getSuperclass().equals(WebMvcConfigurationSupport.class)
                && cls.getAnnotation(Configuration.class) != null
                && !cls.equals(MSWebMvcConfiguration.class)){
            try {
                classListMap.put(cls, ScannerContent.builder()
                        .interceptor(ReflectUtil.getMethod(cls, "addInterceptors", InterceptorRegistry.class))
                        .resourceHandler(ReflectUtil.getMethod(cls, "addResourceHandlers", ResourceHandlerRegistry.class))
                        .argumentResolver(ReflectUtil.getMethod(cls, "addArgumentResolvers", List.class))
                        .build());
            } catch (Exception e){
                log.warn("addInterceptors method invoke error: {}", LogUtil.getExceptionMessage(e));
            }
        }
    }

}
